#include <openssl/evp.h>
#include <iostream>
#include <fstream>
#include <string>

static constexpr uint32_t kBufferSize = 1024;

std::string bytesToHexString(const unsigned char* input, size_t length) {
	static const char lut[] = "0123456789abcdef";
	std::string str;
	str.reserve(length << 1);
	for (size_t i = 0; i < length; ++i) {
		str+= lut[(input[i] >> 4) & 0xF];
		str+= lut[input[i] & 0xF];
	}
	return str;
}

int calc_md5(const char* filename)
{
	int filelen = 0;
	std::ifstream in(filename, std::ios::binary);
	if (!in.is_open()) {
		std::cout << "failed to open: " << filename << std::endl;
		return -1;
	}

	EVP_MD_CTX* ctx;
	ctx = EVP_MD_CTX_new();
	EVP_MD_CTX_init(ctx);
	EVP_DigestInit_ex(ctx, EVP_md5(), NULL);

	std::streamsize length;
	char buffer[kBufferSize];
	while (!in.eof()) {
		in.read(buffer, kBufferSize);
		length = in.gcount();
		if (length > 0) {
			filelen += static_cast<int>(length);
			EVP_DigestUpdate(ctx, buffer, length);
		}
	}
	in.close();

	unsigned char target[256] = { 0 };
	unsigned int target_length = 0;
	EVP_DigestFinal_ex(ctx, target, &target_length);
	EVP_MD_CTX_free(ctx);

	std::cout << "md5: " << bytesToHexString(target, target_length) <<", fileLen: "<< filelen << std::endl;
	return filelen;
}

int main(int argc, char* argv[])
{
	std::string filename = "test.txt";
	int filelen = calc_md5(filename.c_str());
	if (filelen < 0)
	{
		std::cout << "calc_md5 fail!" << std::endl;
		return -1;
	}

	return 0;
}